#ifndef _NOEUD
#define _NOEUD

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<string>

#include "parser.hpp"

using namespace std;

enum e_type {
    t_operateur,
    t_valeur
};

enum operateur {
    o_plus,
    o_mult
};

union elt {
    int valeur;
    operateur op;
};

struct noeud {
    e_type type;
    elt info;
    noeud** fils;
    unsigned int nbFils;
    unsigned int capaFils;
};

/*
    Pour toutes ces fonctions, la variable verbose permet d'afficher des information supplémentaires
    lors de l'éxecution, principalement utiles au débuggage
*/

void initNoeud(noeud &n, unsigned int nb_fils = 0, bool verbose = false);
/* initialise un noeud avec une capacité de nb_fils
   IMPORTANT : aucun fils n'est crée, le tableau de fils est juste initialisé au  nmbre passé en paramètre
               Il faut ensuite racorder les fils au noeud */

void initNoeud(noeud& n, const noeud& copie, bool verbose = false);
/* initialisation d'un noeud par copie
    précondition :  n non initialisé
                    copie initialisé
    postcondition : n initialisé comme copie de copie (emplacements mémoire distinctifs)
                    les descendants de copie sont eux aussi ajoutés recursivement */

void initNoeud(noeud& n, string expression, bool verbose = false);
/* initialisation d'un noeud par une expression
    précondition :  n non initialisé
                    expression une chaine sous forme d'expression polonaise inversée
    postcondition : n initialisé avec l'expression */

void initValeur(noeud &n, int i, bool verbose = false);
/* initialisation d'un noeud avec une valeur
    précondition :  n non initialisé
                    i un entier
    postcondition : n initialisé avec la valeur i. Aucun fils n'est créé */

void initOperateur(noeud& n, operateur op, unsigned int nb_fils = 2, bool verbose = false);
/* initialisation d'un noeud avec un operateur
    précondition :  n non initialisé
                    op un operateur
                    nb_fils un entier positif le nombre de fils avec lequel on initialise l'operateur (par défaut 2)
    postcondition : n initialisé avec l'operateur op. nb_fils fils sonts créés */

void ajoutFils(noeud& parent, noeud* fils, bool verbose = false);
/* ajout d'un noeud par un autre noeud
    précondition :  parent initialisé
                    fils initialisé
    postcondition : fils ajouté aux fils de parent, agrandissement du tableau de fils de parent si necessaire */

void ajoutFils(noeud& parent, elt info, e_type type, unsigned int nb_fils = 0, bool verbose = false);
/* ajout d'un noeud par informations
    précondition :  parent initialisé
                    info un element de type elt
                    type unt type de type e_type
                    nb_fils un entier positif
    postcondition : un fils contenant les informations passé en paramètre est ajouté aux fils de parent
                    agrandissement du tableau de fils de parent si necessaire */

void testamentFils(noeud& parent, bool verbose = false);
/* libére les fils de parent ainsi que son tableau de fils
    précondition :  parent initialisé
    postcondition : les fils et le tableau de fils de parent libéré */

void testamentNoeud(noeud& n, bool verbose = false);
/* libére un noued
    précondition :  n initialisé
    postcondition : n libéré */

void affichageNoeudExpression(const noeud& n, bool racine = false);
/* affiche l'expression d'un noued (utilisé pour l'affichage réucrsif d'un arbre
    précondition :  n initialisé */

void affichageNoeudHorizontal(const noeud& n, int niveau);
/* affiche l'expression d'un noued (utilisé pour l'affichage réucrsif d'un arbre
    précondition :  n initialisé */

void affichageOp(const operateur op, bool gestErr = false);
/*  affiche un operateur
    si gestErr est à true, le programme indique si l'operateur spécifié n'est pas géré par le programme */

/* fonctions de verifications */

bool noeudFeuille (const noeud& n);
/* indique si un noued est une feuille (aka il n'a pas de fils)
    précondition :  n initialisé
    postcondition : renvoie vrai si le noeud est une feuille, faux sinon*/


bool noeudFilsFeuille (const noeud &n);
/* indique si tous les fils d'un noued sont des feuilles (aka ils n'ont pas de fils)
    précondition :  n initialisé
    postcondition : renvoie vrai si tous les fils du noeud sont des feuilles, faux sinon*/

int valeurNoeud (const noeud& n, bool gestErr = false);
/* renvoie l'a valeur d'un fils
    précondition :  n initialisé
                    si gestErr est à true, le programme indique si l'operateur spécifié n'est pas géré par le programme
    postcondition : si n est une feuille, on revoie sa valeur
                    sinon on calcule la valeur du noued en fonction de ces descendants */

void affichageNoeudComplet(const noeud & n);
/*  affiche des informations complètes sur le noeud
    à utiliser pour le débuggage */

#endif
